package com.mathcat.mobile.android.data.account;

import java.util.ArrayList;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

class AccountManagerImpl implements AccountManager {

	private final static String LOGTAG = "AccountManager";
	
	private final static String DATABASE_NAME = "AccountManager";
	private final static int DATABASE_VERSION = 2;
	
	private final static String TABLE_ACCOUNT = "account";
	
	private final static int VALUE_IS_LAST_LOGIN_TRUE = 1;
	private final static int VALUE_IS_LAST_LOGIN_FALSE = 0;
	
	private final static int VALUE_IS_AUTO_LOGIN_TRUE = 1;
	private final static int VALUE_IS_AUTO_LOGIN_FALSE = 0;
	
	private final static int VALUE_IS_PASSWORD_REMEMBERED_TRUE = 1;
	private final static int VALUE_IS_PASSWORD_REMEMBERED_FALSE = 0;
	
	private final static String KEY_UID = "UID";
	private final static String KEY_PASSWORD = "PASSWORD";
	private final static String KEY_IS_LAST_LOGIN = "IS_LAST_LOGIN";
	private final static String KEY_IS_AUTO_LOGIN = "IS_AUTO_LOGIN";
	private final static String KEY_IS_PASSWORD_REMEMBERED = "IS_PASSWORD_REMEMBERED";
	
	private final static String[] TABLE_ACCOUNT_COLUMNS = 
		new String[] {KEY_UID, KEY_PASSWORD, KEY_IS_PASSWORD_REMEMBERED, KEY_IS_LAST_LOGIN, KEY_IS_AUTO_LOGIN};
	private final static String STATEMENT_CREATE_TABLE = "CREATE TABLE " + TABLE_ACCOUNT + " ("
		+ KEY_UID + " text, "
		+ KEY_PASSWORD + " text, "
		+ KEY_IS_PASSWORD_REMEMBERED + " integer, "
		+ KEY_IS_AUTO_LOGIN + " integer, "
		+ KEY_IS_LAST_LOGIN + " integer"
		+ ");"
		;
	
	private Context context;

	private AccountDBOpenHelper helper;
	
	private SQLiteDatabase db;
	
	AccountManagerImpl(Context context) {
		this.context = context;
		
		Log.d(LOGTAG, "Establishing DB AccountManager.");
		this.helper = new AccountDBOpenHelper(context);
		this.db = this.helper.getWritableDatabase();
	}

	public void close() {
		Log.d(LOGTAG, "Closing account DB.");
		this.helper.close();
		Log.d(LOGTAG, "Account DB closed.");
	}
	
	@Override
	public Account[] getAllAccounts() {
		Cursor cursor = this.db.query(TABLE_ACCOUNT, TABLE_ACCOUNT_COLUMNS, null, null, null, null, null);
		ArrayList<AccountImpl> temp = new ArrayList<AccountImpl>();
		if (cursor.moveToFirst()) {
			
			do {
				String uid = cursor.getString(cursor.getColumnIndex(KEY_UID));
				String password = cursor.getString(cursor.getColumnIndex(KEY_PASSWORD));
				boolean isPasswordRemembered = cursor.getInt(cursor.getColumnIndex(KEY_IS_PASSWORD_REMEMBERED)) == VALUE_IS_PASSWORD_REMEMBERED_TRUE;
				boolean isAutoLogin = cursor.getInt(cursor.getColumnIndex(KEY_IS_AUTO_LOGIN)) == VALUE_IS_AUTO_LOGIN_TRUE;
				boolean isLastLogin = cursor.getInt(cursor.getColumnIndex(KEY_IS_LAST_LOGIN)) == VALUE_IS_LAST_LOGIN_TRUE;
				
				AccountImpl account = new AccountImpl(uid, password, isPasswordRemembered, isAutoLogin, isLastLogin);
				temp.add(account);
				
			} while (cursor.moveToNext());
						
		}
		
		cursor.close();
		
		AccountImpl[] ret = null;
		
		if (!temp.isEmpty()) {
			int size = temp.size();
			ret = new AccountImpl[size];
			temp.toArray(ret);
		}
		
		return ret;
	}

	@Override
	public Account getLastLoginAccount() {
		Cursor cursor = this.db.query(TABLE_ACCOUNT, TABLE_ACCOUNT_COLUMNS, KEY_IS_LAST_LOGIN + '=' + VALUE_IS_LAST_LOGIN_TRUE, null, null, null, null);
		AccountImpl ret = null;
		
		if (cursor.moveToFirst()) {
			String uid = cursor.getString(cursor.getColumnIndex(KEY_UID));
			String password = cursor.getString(cursor.getColumnIndex(KEY_PASSWORD));
			boolean isPasswordRemembered = cursor.getInt(cursor.getColumnIndex(KEY_IS_PASSWORD_REMEMBERED)) == VALUE_IS_PASSWORD_REMEMBERED_TRUE;
			boolean isAutoLogin = cursor.getInt(cursor.getColumnIndex(KEY_IS_AUTO_LOGIN)) == VALUE_IS_AUTO_LOGIN_TRUE;
			boolean isLastLogin = cursor.getInt(cursor.getColumnIndex(KEY_IS_LAST_LOGIN)) == VALUE_IS_LAST_LOGIN_TRUE;
			ret = new AccountImpl(uid, password, isPasswordRemembered, isAutoLogin, isLastLogin);
		}

		cursor.close();
		
		return ret;
	}
	
	@Override
	public Account[] getAccountsExceptLastLogin() {
		Cursor cursor = this.db.query(TABLE_ACCOUNT, TABLE_ACCOUNT_COLUMNS, "NOT " + KEY_IS_LAST_LOGIN + '=' + VALUE_IS_LAST_LOGIN_TRUE, null, null, null, null);
		
		ArrayList<AccountImpl> tmp = null;
		
		if (cursor.moveToFirst()) {
			tmp = new ArrayList<AccountImpl>();
			
			do {
				String uid = cursor.getString(cursor.getColumnIndex(KEY_UID));
				String password = cursor.getString(cursor.getColumnIndex(KEY_PASSWORD));
				boolean isPasswordRemembered = cursor.getInt(cursor.getColumnIndex(KEY_IS_PASSWORD_REMEMBERED)) == VALUE_IS_PASSWORD_REMEMBERED_TRUE;
				boolean isAutoLogin = cursor.getInt(cursor.getColumnIndex(KEY_IS_AUTO_LOGIN)) == VALUE_IS_AUTO_LOGIN_TRUE;
				boolean isLastLogin = cursor.getInt(cursor.getColumnIndex(KEY_IS_LAST_LOGIN)) == VALUE_IS_LAST_LOGIN_TRUE;
				tmp.add(new AccountImpl(uid, password, isPasswordRemembered, isAutoLogin, isLastLogin));
			} while (cursor.moveToNext());
		}
		
		cursor.close();
		
		if (tmp != null) {			
			AccountImpl[] ret = new AccountImpl[tmp.size()];
			tmp.toArray(ret);
			return ret;
		} else {
			return null;
		}
	}

	@Override
	public boolean removeAccount(String uid) {
		int cnt = db.delete(TABLE_ACCOUNT, KEY_UID + "='" + uid + '\'', null);
		boolean res;
		if (cnt == 0) {
			Log.d(LOGTAG, "No such user in database.");
			res = false;
		} else {
			Log.d(LOGTAG, "Account of user \"" + uid + "\" has been deleted.");
			res = true;
		}
		return res;
	}

	@Override
	public void removeAllAcount() {
		Log.d(LOGTAG, "Removing all accounts info in database.");
		db.delete(TABLE_ACCOUNT, null, null);
	}
	
	@Override
	public void setLastLoginAccount(String uid, String password, boolean isPasswordRemembered, boolean isAutoLogin) {
		Log.d(LOGTAG, "Setting last login account: uid=" + uid + ", password="
				+ password + ", isPasswordRemembered=" + isPasswordRemembered + ", isAutoLogin=" + isAutoLogin);
		
		Cursor cursor = db.query(TABLE_ACCOUNT, TABLE_ACCOUNT_COLUMNS, KEY_UID + "='" + uid + '\'', null, null, null, null);		
		
		if (cursor.moveToFirst()) {
			boolean isLastLogin = cursor.getInt(cursor.getColumnIndex(KEY_IS_LAST_LOGIN)) == VALUE_IS_LAST_LOGIN_TRUE;
			if (!isLastLogin) {
				negateLastLoginAccount();

				ContentValues value = new ContentValues();
				value.put(KEY_PASSWORD, password);
				value.put(KEY_IS_PASSWORD_REMEMBERED, isPasswordRemembered ? VALUE_IS_PASSWORD_REMEMBERED_TRUE : VALUE_IS_PASSWORD_REMEMBERED_FALSE);
				value.put(KEY_IS_AUTO_LOGIN, isAutoLogin ? VALUE_IS_AUTO_LOGIN_TRUE : VALUE_IS_AUTO_LOGIN_FALSE);
				value.put(KEY_IS_LAST_LOGIN, VALUE_IS_LAST_LOGIN_TRUE);
				
				db.update(TABLE_ACCOUNT, value, KEY_UID + "='" + uid + '\'', null);
			} else {
				Log.d(LOGTAG, "This account was exactly the last-login account, update other fields.");
				
				ContentValues value = new ContentValues();
				value.put(KEY_PASSWORD, password);
				value.put(KEY_IS_PASSWORD_REMEMBERED, isPasswordRemembered ? VALUE_IS_PASSWORD_REMEMBERED_TRUE : VALUE_IS_PASSWORD_REMEMBERED_FALSE);
				value.put(KEY_IS_AUTO_LOGIN, isAutoLogin ? VALUE_IS_AUTO_LOGIN_TRUE : VALUE_IS_AUTO_LOGIN_FALSE);
				
				db.update(TABLE_ACCOUNT, value, KEY_UID + "='" + uid + '\'', null);
			}
		} else {
			negateLastLoginAccount();
			
			Log.d(LOGTAG, "Adding new last-login account to db: uid=" + uid
					+ ", password=" + password + ", isPasswordRemembered=" + isPasswordRemembered + ", isAutoLogin=" + isAutoLogin);
			
			ContentValues value = new ContentValues();
			value.put(KEY_UID, uid);
			value.put(KEY_PASSWORD, password);
			value.put(KEY_IS_PASSWORD_REMEMBERED, isPasswordRemembered ? VALUE_IS_PASSWORD_REMEMBERED_TRUE : VALUE_IS_PASSWORD_REMEMBERED_FALSE);
			value.put(KEY_IS_AUTO_LOGIN, isAutoLogin ? VALUE_IS_AUTO_LOGIN_TRUE : VALUE_IS_AUTO_LOGIN_FALSE);
			value.put(KEY_IS_LAST_LOGIN, VALUE_IS_LAST_LOGIN_TRUE);
			
			db.insert(TABLE_ACCOUNT, null, value);
		}
		
		cursor.close();
	}

	private void negateLastLoginAccount() {
		ContentValues value = new ContentValues();
		value.put(KEY_IS_LAST_LOGIN, VALUE_IS_LAST_LOGIN_FALSE);
		
		db.update(TABLE_ACCOUNT, value, KEY_IS_LAST_LOGIN + '=' + VALUE_IS_LAST_LOGIN_TRUE, null);
	}
	
	private class AccountDBOpenHelper extends SQLiteOpenHelper {

		public AccountDBOpenHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			Log.d(LOGTAG, "Creating DB table " + TABLE_ACCOUNT + ", SQL script: " + STATEMENT_CREATE_TABLE);
			db.execSQL(STATEMENT_CREATE_TABLE);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			// TODO Auto-generated method stub
		}
		
	}
}
